Some Behavioural Design Patterns

Brioche/Aspirine

00 - Table of Contents

01 - Introduction
02 - Strategy
03 - Template Method
04 - Chain of Responsibility
05 - Observer or Publisher-Subscriber
06 - Other Behavioural Patterns

01 - Introduction

Everyone knows that the behaviour of an object is described by its methods. One could add that it is also described by the type of the object since a method named resize() doesn't not the same job in the Sprite class than in the Surface_Cache class.

The behaviour of the objects can be defined at run time with late binding mechanisms (provided by virtual methods in C++).

02 - Strategy

A Strategy basically defines a family of interchangeable algorithms.

The Strategy Pattern allows the coder the change the algorithm without having to modify the client. As the following OMT figure shows, a reference to an abstract strategy is hold in the client (also called Context in the scope of this Pattern).


		       contains
			   .
	     ---------	   .	  --------
	    | Context |<>--------|Strategy|
	     ---------		  --------
				      |. . . . . inherits
				     /_\
			 +-------------------------+
			 |	      | 	   |
		     ---------	  ---------    ---------
		    |Strategy1|  |Strategy2|  |Strategy3|
		     ---------	  ---------    ---------

This Pattern is very helpful when a large number of classes differs only by their behaviour. It also allows you to change the behaviour of a class in the time.

And when it comes to add a new behaviour to the context, you just have to write a new concrete Strategy without having to interfere in the core implementation of the client.

This pattern has been used in the Introduction article to design a simple image loading framework.

03 - Template Method

The goal of the Template Method Pattern is to define the skeleton of an algorithm in one method with some parts of the algotihm are implemented by sub-classes. Here's the example of a Texture Mapping class that use a screen wide look-up table to find the (u,v) for each pixel on screen. This is the kind of algorithm used for texture mapped tunnels and similar effects.


	// The root class of all Texture_Mapper based effect
	class Texture_Mapper {
	       // ...
	public:
	       // ...
	       void update( float time );
	       void draw( Surface *surface );
	       // here's the Template Method
	       void calc_table();

	protected:
	       // primitive operations
	       virtual void calc_setup();
	       virtual void calc_uv( float x, float y, int &u, int &v );
	};

	// Empty operations by default
	void Texture_Mapper::calc_setup() {};
	void Texture_Mapper::calc_uv( float x,float y,int &u,int &v ) {}

	// of course, this is unoptimized example code...
	void Texture_Mapper::calc_table() {
		// call the initialization part of the algorithm
		calc_setup();
		// for each pixel of a 320x240 screen
		for ( float y = -120; y < 120; y++ )
			for ( float x = -160; x < 160; x++ ) {
				calc_uv( x, y, *utable, *vtable );
				utable++, vtable++;
			}
	}

	// A simple and uncomplete example of Texture_Mapper
	class Tunnel : public Texture_Mapper {
		float rad;
	public:
		Tunnel( float radius );
		void calc_uv( float x, float y, int &u, int &v );
	};

	// no need for setup code, we just keep the default behaviour
	void Tunnel::calc_uv( float x, float y, int &u, int &v )
	{
		float xx = x+EPSILON;
		float a = atan(y/xx);
		u = int(fabs(cos(a)*rad/xx));
		v = int(a*256.0/M_PI);
	}

The previous example allows you to write an infinity of various Texture Mappers without having with the table calculation algorithm written only once.

To prevent sub-classes from overriding the Template Method, it is declared as non virtual.

With this Pattern, you only have to implement once the "static" parts of algorithm by factorizing the common behaviour in the parent class.

04 - Chain of Responsibility

The aim of this pattern is to delegate a request when class can't handle it.


			   calls      +--------+
			     .	      |        |
		   ------    .	   -------     |
		  |Client|------->|Handler|<>--+
		   ------	   -------
				      |
				     /_\
			 +-------------------------+
			 |	      | 	   |
		      --------	   --------	--------
		     |Handler1|   |Handler2|   |Handler3|
		      --------	   --------	--------

The client sends a request to a Handler inheriting from an abstract Handler that holds a reference to a successor handler to be used if we can't handle the request.

This pattern is often used with Composite. The chain used then is simply the relations in the Composite pattern. Such a pattern is also often used for event and error handling (rethrowing exception in the catch statement). Some example code follows :


	// Base Handler
	class Handler {
		Handler *succ;
	public:
		//
		Handler( Handler *s ) : succ(s) {}
		// Default behaviour of the handler
		virtual void handle() { if ( succ ) suff->handle(); }
	};

	// Custom Handler
	class Handler1 : public Handler {
	public:
		Handler1( Handler *s );
		void handle();
	}

	Handler1::Handler1( Handler *s ) : Handler(s)
	{
		// Internal setup of custom handler
		...
	}

	void Handler1::handle()
	{
		if ( i_can_handle_the_request )
			// do the right stuff
		else
			Handler::handle();

	}

If you have several request, you can either write several methods or multiplex them in a single argument driven method.

When you send a request to a Chain of Responsibility, you don't know which class will process the query. Neither does the handling class knows which client sent the request.

05 - Observer or Publisher-Subscriber

This pattern allows an "Observable" (aka Master, Publisher) object to notify one or more observers (aka Slaves, Subscribers) when its state changes.


	--------------- 	    ----------
       |   Publisher   |----------O|Subscriber|
       |---------------|	   |----------|
       |att(Subscriber)|	   |callback()| - - - - abstract method
       |det(Subscriber)|	    ----------
       |notify()       |		|
	--------------- 		|
	       |			|
	      /_\		       /_\
	       |			|
	   ----------		    -----------
	  |Publisher1|		   |Subscriber1|
	  |----------|		   |-----------|
	  |state     |		   |callback() | - - - - concrete method
	   ----------		    -----------

On each modification of the state of the Publisher, its notify() method just invoque the callback() method of all the subscribed objects.

To avoid inheritance issues (i.e. notifying all the objects before updating the state in the child class), it's usually a good idea to design the notify() method as a template method (see section 03).

The Subscriber class will probably need information about the event that triggered the notification process. This may be done in basically two ways:

- the PUSH method: you pass all the information to the Subscriber, whatever it needs it or not. The advantage is that the communication protocol is simple but a large amount of data might have to be transferred.

- the PULL method: the Subscriber must request all the information it needs to accomplish its task. The protocol is more complex but it might be faster too.

The choice of the right method really depends on the context.

To increase the efficiency of the system, you can improve the granularity of the system by allowing the observers to subscribe only for a given set of events. This doesn't involve tremendous changes in the interface and can really speed things up.

Some might have noticed that this pattern is the cornerstone of the whole event system of the Java Abstract Windowing Toolkit 1.1.

This pattern can be used to notify clients when cached data (like surfaces in a 3D engine for instance) becomes outdated.

06 - Other Behavioural Patterns

There are much more Behavioural Patterns but I'm kinda busy for the moment and I miss time to cover them in this document. Drop me email if you want to see other Patterns developped in your favorite column!

Btw, cut-n-paste really rocks! =)

For you informations, here's a brief description of some other Behavioural Patterns:

- Command, when and how to process a request
- Iterator, how to wander in a container
- Interpreter, the grammar and the interpretation of a language
- Memento, which private is stored in the object and when
- Visitor, operations to apply to an object without modifying its class

brioche of the aspirine d-zign international demo brigade